/*
 * =====================================================================================
 *
 *       Filename:  test_mutex.cxx
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  10/09/2010 12:02:55 AM
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  Ken Chen (Ziliang), zlchen.ken@gmail.com
 *        Company:  EMC
 *
 * =====================================================================================
 */

#include <memory>
#include <functional>
#include <utility>
#include <iostream>
#include "cl_lock.hxx"
#include "cl_mutex.hxx"
#include "cl_cond_mutex.hxx"
#include "cl_pc_queue.hxx"
#include "cl_thread.hxx"
#include "cl_singleton.hxx"
#include "cl_callback.hxx"

using namespace std;
using namespace neo;

class Consumer
{
public:
	Consumer()
	{
    m_thr = unique_ptr<CLThread>(new CLThread(bind(&Consumer::consume, this)));
  }
	
  ~Consumer()
	{
		m_thr->join();
	}

  void startConsume( void )
  {
		m_thr->start();
  }

	void consume( void )
	{
    bool result = false;
    for( ; ; )
    {
      unique_ptr<int> up; 
      result = CLSingleton<CLProducerConsumerQueue< unique_ptr<int> > >::instance()->pop(up);
      if(result)
      {
        cout << "Consumed unique_ptr " << *(up.get()) << "\n";
      }
    }
  }

private:
	unique_ptr<CLThread> m_thr;
};

class Producer
{
public:
	Producer()
	{
	  m_thr = unique_ptr<CLThread>(new CLThread(bind(&Producer::produce, this)));
  }

  ~Producer()
	{
		m_thr->join();
	}

	void startProduce( void )
	{
		m_thr->start();
	}

	void produce( void )
	{
    int i = 0;
		//int j = 0;
    for( ; ; )
    {
      CLSingleton<CLProducerConsumerQueue< unique_ptr<int> > >::instance()->push( unique_ptr<int>(new int(++i)) );
      cout << "Produced unique_ptr " << i << "\n";
			sleep(1);
     }
	}

private:
	unique_ptr<CLThread> m_thr;
};


int main( int argc, char *argv[] )
{
  // Init the queue
  CLSingleton<CLProducerConsumerQueue< unique_ptr<int> > >::create();
  CLSingleton<CLProducerConsumerQueue<int> >::create();

  // Start up the producer thread
  Producer pt1;
  pt1.startProduce();

  //Producer pt2;
  //pt2.startProduce();

  sleep(3);
  // Start up the consumer threads
  Consumer ct1;
  ct1.startConsume();

#if 0
  Consumer ct2;
  ct2.startConsume();

  Consumer ct3;
  ct3.startConsume();
#endif 

	return 0;
}

